package ru.amse.stroganova.ui.action;

import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.KeyStroke;

import ru.amse.stroganova.ui.GraphComponent;
import ru.amse.stroganova.ui.command.Command;
import ru.amse.stroganova.ui.layout.CircleLayout;
import ru.amse.stroganova.ui.layout.Layout;

/**
 * Presents a factory for graph component editing actions.
 * 
 * @author Dasha Stroganova
 * 
 */
//TODO if nesessary make all action classes package private and detach them.
public class EditingActionsFactory {

	private final GraphComponent component;
	
	private final ToggleAction selectAction;

	private final ToggleAction addVertexAction;

	private final ToggleAction addEdgeAction;

	private final Action deleteAction;

	private final Action circleLayoutAction;

	private final Action undoAction;

	private final Action redoAction;
	
	private final Action discardHighlightingAction;
	
	private boolean isSelectActive = false;
	
	/**
	 * Creates new editing actions factory for givat graph component.
	 * 
	 * @param component
	 */
	public EditingActionsFactory(GraphComponent component) {
		this.component = component;
		
		selectAction = new SelectAction();
		addVertexAction = new AddVertexAction();
		addEdgeAction = new AddEdgeAction();
		deleteAction = new DeleteAction();
		circleLayoutAction = new CircleLayoutAction();
		undoAction = new UndoAction();
		redoAction = new RedoAction();
		discardHighlightingAction = new DiscardHighlightingAction();
	}
	
	/**
	 * Returns an action for selecting mode.
	 * 
	 * @return action
	 */
	public ToggleAction getSelectAction() {
		return selectAction;
	}

	/**
	 * Returns an action for adding vertices mode.
	 * 
	 * @return action
	 */
	public ToggleAction getAddVertexAction() {
		return addVertexAction;
	}

	/**
	 * Returns an action for adding edges mode.
	 * 
	 * @return action
	 */
	public ToggleAction getAddEdgeAction() {
		return addEdgeAction;
	}

	/**
	 * Returns an action for deleting items.
	 * 
	 * @return action
	 */
	public Action getDeleteAction() {
		return deleteAction;
	}

	/**
	 * Returns an action for layout.
	 * 
	 * @return action
	 */
	public Action getCircleLayoutAction() {
		return circleLayoutAction;
	}
	
	/**
	 * Return an action for manually discaring highlighting.
	 * 
	 * @return action
	 */
	public Action getDiscardHighlightingAction() {
		return discardHighlightingAction;
	}

	/**
	 * Returns an action for undo.
	 * 
	 * @return action
	 */
	public Action getUndoAction() {
		return undoAction;
	}

	/**
	 * Returns an action for redo.
	 * 
	 * @return action
	 */
	public Action getRedoAction() {
		return redoAction;
	}
	
	/**
	 * @return the isSelectActive
	 */
	public boolean isSelectActive() {
		//XXX BAD IDEA
		return isSelectActive;
	}
	
	private class SelectAction extends ToggleAction {

		/* package */SelectAction() {
			super("Select");
			putValue(SHORT_DESCRIPTION, "Select");
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/select.gif")));
			setEnabled(false);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			super.actionPerformed(e);
			isSelectActive = true;
			component.setTool(component.getToolFactory().getSelectTool());
			putValue("NAME", "Select");
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/select.gif")));
			component.getAlgorythmActionsFactory().messageUnactive();
		}

	}

	private class AddVertexAction extends ToggleAction {

		/* package */AddVertexAction() {
			super("Add vertex");
			putValue(SHORT_DESCRIPTION, "Add vertex");
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/add_vertex.gif")));
			setEnabled(false);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			super.actionPerformed(e);
			isSelectActive = false;
			component.setTool(component.getToolFactory().getAddVertexTool());
			deleteAction.setEnabled(false);
		}
	}

	private class AddEdgeAction extends ToggleAction {

		/* package */AddEdgeAction() {
			super("Add Edge");
			putValue(SHORT_DESCRIPTION, "Add Edge");
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/add_edge.gif")));
			setEnabled(false);
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			super.actionPerformed(e);
			isSelectActive = false;
			component.setTool(component.getToolFactory().getAddEdgeTool());
			deleteAction.setEnabled(false);
		}

	}

	private class DeleteAction extends AbstractAction {

		/* package */DeleteAction() {
			super("Delete");
			putValue(SHORT_DESCRIPTION, "Delete");
			putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(
					KeyEvent.VK_DELETE, 0));
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/delete.gif")));
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent e) {
			Command command = component.getCommandFactory().getNewDeleteCommand();
			component.addCommand(command);
			command.execute();
		}
	}

	private class UndoAction extends AbstractAction {

		/* package */UndoAction() {
			super("Undo");
			putValue(SHORT_DESCRIPTION, "Undo");
			putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Z,
					KeyEvent.CTRL_MASK));
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/undo.gif")));
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent e) {
			component.getUndoBuffer().undo();
			redoAction.setEnabled(true);
			if (!component.getUndoBuffer().hasUndo()) {
				component.setWasChanged(false);
				setEnabled(false);
			}
		}
	}

	private class RedoAction extends AbstractAction {

		/* package */RedoAction() {
			super("Redo");
			putValue(SHORT_DESCRIPTION, "Redo");
			putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Y,
					KeyEvent.CTRL_MASK));
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/redo.gif")));
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent e) {
			component.getUndoBuffer().redo();
			undoAction.setEnabled(true);
			if (!component.getUndoBuffer().hasRedo()) {
				setEnabled(false);
			}
			component.setWasChanged(true);
		}
	}

	private class CircleLayoutAction extends AbstractAction {

		/* package */CircleLayoutAction() {
			super("Circle Layout");
			putValue(SHORT_DESCRIPTION, "Circle Layout");
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/circle.gif")));
			putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_L,
					KeyEvent.CTRL_MASK));
			setEnabled(false);
		}

		public void actionPerformed(ActionEvent e) {
			Layout circleLayout = new CircleLayout(component.getGraphPresentation(), new Point(component.getWidth(), component.getHeight()));
			Command command = component.getCommandFactory().getNewLayoutCommand(circleLayout);
			component.addCommand(command);
			command.execute();
		}
	}

	private class DiscardHighlightingAction extends AbstractAction {

		/*package*/ DiscardHighlightingAction() {
			super("Unmark");
			putValue(SHORT_DESCRIPTION, "Discard Highlighting");
			putValue(SMALL_ICON, new ImageIcon(ClassLoader.getSystemResource("img/unmark.gif")));
			putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_D,
					KeyEvent.CTRL_MASK));
			setEnabled(false);
		}
		
		public void actionPerformed(ActionEvent e) {
			component.getGraphElementMarker().unmark();
		}
		
	}

	
}
